/**
 * advanced_test.c - 用于测试增强钩子框架的高级测试应用程序
 *
 * 此程序测试各种钩子功能，包括文件I/O、网络、进程、内存和系统钩子。
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/utsname.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <time.h>

#define TEST_PORT 8080
#define TEST_BUFFER_SIZE 1024

// 添加的调试宏
#define DEBUG_PRINT(fmt, ...) do { fprintf(stdout, "DEBUG [%s:%d]: " fmt "\n", __func__, __LINE__, ##__VA_ARGS__); fflush(stdout); } while(0)

/**
 * 测试文件I/O操作
 */
static void test_file_io(void) {
    DEBUG_PRINT("开始测试文件IO操作");
    printf("\n=== 测试文件I/O操作 ===\n");
    
    /* 测试低级文件操作 */
    printf("正在使用open()打开文件'test_output.txt'...\n");
    int fd = open("test_output.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (fd < 0) {
        perror("打开文件失败");
    } else {
        const char *data = "这是使用write()写入的测试数据。\n";
        printf("正在使用write()写入数据...\n");
        ssize_t written = write(fd, data, strlen(data));
        printf("已写入%zd字节\n", written);
        
        printf("正在使用close()关闭文件...\n");
        close(fd);
    }
    
    /* 测试高级文件操作 */
    printf("\n正在使用fopen()打开文件'test_output2.txt'...\n");
    FILE *fp = fopen("test_output2.txt", "w");
    if (!fp) {
        perror("打开文件失败");
    } else {
        const char *data = "这是使用fprintf()写入的测试数据。\n";
        printf("正在使用fprintf()写入数据...\n");
        fprintf(fp, "%s", data);
        
        printf("正在使用fclose()关闭文件...\n");
        fclose(fp);
    }
    
    /* 测试读取文件 */
    printf("\n正在使用open()/read()读取文件'test_output.txt'...\n");
    fd = open("test_output.txt", O_RDONLY);
    if (fd < 0) {
        perror("打开文件读取失败");
    } else {
        char buffer[TEST_BUFFER_SIZE];
        ssize_t bytes_read = read(fd, buffer, sizeof(buffer) - 1);
        if (bytes_read > 0) {
            buffer[bytes_read] = '\0';
            printf("已读取%zd字节: %s", bytes_read, buffer);
        } else {
            perror("从文件读取失败");
        }
        close(fd);
    }
    
    /* 测试文件状态 */
    printf("\n正在使用stat()获取文件信息...\n");
    struct stat st;
    if (stat("test_output.txt", &st) == 0) {
        printf("文件大小: %ld 字节\n", (long)st.st_size);
        printf("文件权限: %o\n", st.st_mode & 0777);
        printf("最后修改时间: %ld\n", (long)st.st_mtime);
    } else {
        perror("获取文件状态失败");
    }
    DEBUG_PRINT("文件IO测试完成");
}

/**
 * 测试网络操作
 */
static void test_network(void) {
    DEBUG_PRINT("开始测试网络操作");
    printf("\n=== 测试网络操作 ===\n");
    
    /* 创建套接字 */
    printf("正在创建套接字...\n");
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        perror("创建套接字失败");
        return;
    }
    
    /* 尝试连接到本地端口 */
    printf("尝试连接到127.0.0.1:%d...\n", TEST_PORT);
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(TEST_PORT);
    inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);
    
    int result = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr));
    if (result < 0) {
        printf("连接失败（如果端口%d没有服务在监听则为预期结果）\n", TEST_PORT);
    } else {
        printf("连接成功\n");
        
        /* 发送一些数据 */
        const char *msg = "来自advanced_test的问候！";
        printf("发送消息: '%s'\n", msg);
        send(sockfd, msg, strlen(msg), 0);
        
        /* 接收响应 */
        char buffer[TEST_BUFFER_SIZE];
        ssize_t received = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
        if (received > 0) {
            buffer[received] = '\0';
            printf("收到响应: %s\n", buffer);
        } else {
            printf("未收到响应\n");
        }
    }
    
    /* 关闭套接字 */
    printf("正在关闭套接字...\n");
    close(sockfd);
    
    /* 尝试连接到22端口(SSH) - 应该被钩子阻止 */
    printf("\n尝试连接到127.0.0.1:22（应被阻止）...\n");
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        perror("创建套接字失败");
        return;
    }
    
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(22);  /* SSH端口 */
    inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);
    
    result = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr));
    if (result < 0) {
        printf("连接被阻止（预期结果）\n");
    } else {
        printf("连接到22端口（意外结果）\n");
        close(sockfd);
    }
    DEBUG_PRINT("网络测试完成");
}

/**
 * 测试进程操作
 */
static void test_process(void) {
    DEBUG_PRINT("开始测试进程操作");
    printf("\n=== 测试进程操作 ===\n");
    
    /* 测试fork */
    printf("正在调用fork()...\n");
    pid_t pid = fork();
    
    if (pid < 0) {
        perror("fork失败");
    } else if (pid == 0) {
        /* 子进程 */
        printf("这是子进程（PID=%d）\n", getpid());
        printf("子进程的父进程ID是: %d\n", getppid());
        exit(0);
    } else {
        /* 父进程 */
        printf("这是父进程（PID=%d），子进程PID是: %d\n", getpid(), pid);
        
        /* 等待子进程结束 */
        int status;
        waitpid(pid, &status, 0);
        printf("子进程已退出，状态: %d\n", WEXITSTATUS(status));
    }
    
    /* 测试system */
    printf("\n正在使用system()执行命令...\n");
    int ret = system("echo '这是通过system()执行的命令'");
    printf("system()返回: %d\n", ret);
    
    /* 测试危险命令 */
    printf("\n尝试执行危险命令（应被阻止）...\n");
    ret = system("rm -rf /tmp/test_dir");
    if (ret != 0) {
        printf("危险命令被阻止（预期结果）\n");
    } else {
        printf("危险命令被执行（意外结果）\n");
    }
    
    /* 显示进程ID */
    printf("\n进程ID = %d\n", getpid());
    printf("父进程ID = %d\n", getppid());
    printf("用户ID = %d\n", getuid());
    printf("有效用户ID = %d\n", geteuid());
    DEBUG_PRINT("进程测试完成");
}

/**
 * 测试系统信息
 */
static void test_system_info(void) {
    DEBUG_PRINT("开始测试系统信息");
    printf("\n=== 测试系统信息 ===\n");
    
    /* 测试环境变量 */
    printf("HOME = %s\n", getenv("HOME") ? getenv("HOME") : "（未设置）");
    printf("USER = %s\n", getenv("USER") ? getenv("USER") : "（未设置）");
    printf("PATH = %s\n", getenv("PATH") ? getenv("PATH") : "（未设置）");
    printf("PLUGIN_TEST = %s\n", getenv("PLUGIN_TEST") ? getenv("PLUGIN_TEST") : "（未设置）");
    
    /* 测试时间函数 */
    time_t now = time(NULL);
    printf("\n当前时间戳: %ld\n", (long)now);
    printf("当前时间: %s", ctime(&now));
    
    /* 测试gettimeofday */
    struct timeval tv;
    gettimeofday(&tv, NULL);
    printf("gettimeofday: %ld.%06ld\n", (long)tv.tv_sec, (long)tv.tv_usec);
    
    /* 测试系统信息 */
    struct utsname un;
    if (uname(&un) == 0) {
        printf("\n系统信息:\n");
        printf("  系统名称: %s\n", un.sysname);
        printf("  主机名: %s\n", un.nodename);
        printf("  发行版: %s\n", un.release);
        printf("  版本: %s\n", un.version);
        printf("  硬件: %s\n", un.machine);
    }
    
    /* 测试主机名 */
    char hostname[256];
    if (gethostname(hostname, sizeof(hostname)) == 0) {
        printf("\n主机名: %s\n", hostname);
    } else {
        perror("获取主机名失败");
    }
    DEBUG_PRINT("系统信息测试完成");
}

/**
 * 测试内存操作
 */
static void test_memory(void) {
    DEBUG_PRINT("===开始测试内存操作===");
    printf("\n=== 测试内存操作 ===\n");
    
    /* 测试malloc/free */
    DEBUG_PRINT("准备测试malloc");
    printf("正在使用malloc()分配内存...\n");
    void *ptr = malloc(1024);
    DEBUG_PRINT("malloc(1024)返回: %p", ptr);
    
    if (ptr) {
        printf("已分配1024字节内存\n");
        
        /* 写入一些数据 */
        DEBUG_PRINT("准备写入数据");
        memset(ptr, 'A', 1024);
        printf("已写入数据\n");
        
        /* 释放内存 */
        DEBUG_PRINT("准备释放内存");
        printf("正在使用free()释放内存...\n");
        free(ptr);
        DEBUG_PRINT("内存已释放");
    } else {
        printf("内存分配失败\n");
    }
    
    /* 测试calloc */
    DEBUG_PRINT("准备测试calloc");
    printf("\n正在使用calloc()分配内存...\n");
    int *array = (int *)calloc(10, sizeof(int));
    DEBUG_PRINT("calloc(10, %zu)返回: %p", sizeof(int), array);
    
    if (array) {
        printf("已分配10个整数的内存\n");
        
        /* 检查是否已初始化为0 */
        int sum = 0;
        DEBUG_PRINT("检查calloc内存初始化");
        for (int i = 0; i < 10; i++) {
            sum += array[i];
        }
        printf("数组和（应为0）: %d\n", sum);
        
        /* 写入数据 */
        DEBUG_PRINT("写入数据到calloc分配的内存");
        for (int i = 0; i < 10; i++) {
            array[i] = i;
        }
        
        /* 测试realloc */
        DEBUG_PRINT("准备测试realloc");
        printf("\n正在使用realloc()重新分配内存...\n");
        int *new_array = (int *)realloc(array, 20 * sizeof(int));
        DEBUG_PRINT("realloc返回: %p", new_array);
        
        if (new_array) {
            printf("已重新分配20个整数的内存\n");
            
            /* 检查原始数据是否保留 */
            sum = 0;
            DEBUG_PRINT("验证realloc后的数据");
            for (int i = 0; i < 10; i++) {
                sum += new_array[i];
            }
            printf("前10个元素的和（应为45）: %d\n", sum);
            
            /* 释放内存 */
            DEBUG_PRINT("释放realloc的内存");
            printf("正在使用free()释放内存...\n");
            free(new_array);
            DEBUG_PRINT("内存已释放");
        } else {
            printf("内存重新分配失败\n");
            free(array);
        }
    } else {
        printf("内存分配失败\n");
    }
    DEBUG_PRINT("内存测试完成");
}

int main(int argc, char *argv[]) {
    /* 打印启动消息 */
    DEBUG_PRINT("程序启动");
    printf("钩子框架高级测试应用程序\n");
    printf("==============================\n");
    DEBUG_PRINT("解析命令行参数");
    
    /* 检查是否给定了特定测试 */
    if (argc > 1) {
        DEBUG_PRINT("指定了测试类型: %s", argv[1]);
        if (strcmp(argv[1], "file") == 0) {
            test_file_io();
        } 
        else if (strcmp(argv[1], "network") == 0) {
            test_network();
        } 
        else if (strcmp(argv[1], "process") == 0) {
            test_process();
        }
        else if (strcmp(argv[1], "system") == 0) {
            test_system_info();
        }
        else if (strcmp(argv[1], "memory") == 0) {
            test_memory();
        }
        else {
            printf("未知测试: %s\n", argv[1]);
            printf("可用测试: file, network, process, system, memory\n");
        }
    } 
    else {
        /* 运行所有测试 */
        DEBUG_PRINT("未指定测试类型，运行所有测试");
        test_file_io();
        test_network();
        test_process();
        test_system_info();
        test_memory();
    }
    
    printf("\n所有测试已完成。\n");
    DEBUG_PRINT("程序正常退出");
    
    return 0;
} 